
"""
装饰器应用场景
    - 日志、监控、权限、设计、参数检查、路由等处理。
    - 这些功能与业务功能无关，很多业务都需要的公共功能、所以适合独立出来、需要的时候对目标对象增强
"""
import time
import datetime
from functools import wraps
import inspect

def cus_cache(duration):
    def _cache(fn):
        my_cache = {}
        @wraps(fn)
        def wrapper(*args, **kwargs):
            # 自动过期功能
            invalid_cache = []
            for k, (_, ts) in my_cache.items():
                if datetime.datetime.now().timestamp() - ts > duration:
                    invalid_cache.append(k)
            for k in invalid_cache:
                my_cache.pop(k)


            print("22")
            # 注解签名
            sig = inspect.signature(fn)
            parameter = sig.parameters  # 有序字典

            # 定义一个空字典, 用来存放传进来的的实参的k、v，缺少值的k、v
            key_dict = {}
            # 位置参数处理
            parameter_list = list(parameter.keys())
            for index, v in enumerate(args):
                key = parameter_list[index]
                key_dict[key] = v

            # 关键字参数处理
            key_dict.update(kwargs)

            # 缺少值参数处理
            for k in parameter.keys():
                if k not in key_dict.keys():
                    key_dict[k] = parameter[k].default

            key = tuple(sorted(key_dict.items()))
            if key not in my_cache.keys():
                ret = fn(*args, **kwargs)
                my_cache[key] = (ret, datetime.datetime.now().timestamp())

            return my_cache[key]
        return wrapper
    return _cache

def run_time(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        print("11")
        start = datetime.datetime.now()
        ret = fn(*args, **kwargs)
        delta = (datetime.datetime.now() - start).total_seconds()
        # print(delta)
        return ret
    return wrapper

def sleep_time(fn):
    @wraps(fn)
    def wrapper(*args, **kwargs):
        print("00")
        time.sleep(3)
        ret = fn(*args, **kwargs)
        return ret
    return wrapper


@run_time   # 函数名替换时，下面先进行，运行时谁在上面先执行哪个
@cus_cache(5)
@sleep_time
def add(x,y,z=1):
    # time.sleep(3)
    ret = x + y
    return ret

print(add(1,z=1,y=1))
print(add(1,2))

